// Copyright Leonid Shlyapnikov 2010
// Distributed under the GNU Lesser General Public License http://www.gnu.org/licenses/lgpl.html
//    author: Leonid Shlyapnikov, created on: Feb 1, 2010

#include <boost/test/test_tools.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/mpl/assert.hpp>

#include <boost/mpl/list.hpp>
#include <boost/mpl/list_c.hpp>

#include <stdexcept>

#include "../../main/fixparser/Tag.h"
#include "../../main/fixparser/log.h"
#include "../../main/fixparser/MemoryArea.h"


using fixparser::Tag;

struct RegisteredTags {
    typedef boost::mpl::list< Tag<100>, Tag<101>, Tag<102>, Tag<103>, Tag<104> >::type cached_tags_mpl_list;
};

//struct RegisteredTags3 {
//    typedef boost::mpl::list_c< int, 1000, 1001, 1002, 1003, 1004 >::type list;
//};


//template<size_t TAG_NUM, typename CACHED_TAGS_LIST_T>
//struct mpl_tag_index2 {
////    BOOST_MPL_ASSERT( boost::mpl:is_sequence< typename CACHED_TAGS_T::cached_tags_mpl_list > );
//    static const int result = boost::mpl::index_of< typename CACHED_TAGS_LIST_T, TAG_NUM >::type::value;
//};

void Tag_test() {
    using fixparser::mpl_tag_index;

    BOOST_MPL_ASSERT_RELATION( (mpl_tag_index<100, RegisteredTags>::result), ==, 0 );
    LOG_DEBUG("hash_code of tag100: " << (mpl_tag_index<100, RegisteredTags>::result));

    BOOST_MPL_ASSERT_RELATION( (mpl_tag_index<101, RegisteredTags>::result), ==, 1 );
    LOG_DEBUG("hash_code of tag101: " << (mpl_tag_index<101, RegisteredTags>::result));

    BOOST_MPL_ASSERT_RELATION( (mpl_tag_index<102, RegisteredTags>::result), ==, 2 );
    LOG_DEBUG("hash_code of tag102: " << (mpl_tag_index<102, RegisteredTags>::result));

    BOOST_MPL_ASSERT_RELATION( (mpl_tag_index<103, RegisteredTags>::result), ==, 3 );
    BOOST_MPL_ASSERT_RELATION( (mpl_tag_index<104, RegisteredTags>::result), ==, 4 );


//    typedef boost::mpl::list_c< int, 1000, 1001, 1002, 1003, 1004 >::type list;
//    int index = mpl_tag_index2<list, 1001>;
//    LOG_DEBUG("index: " << index);
}

void Tag_test_get_number_of_decimal_digits() {
    using fixparser::get_number_of_decimal_digits;

    BOOST_CHECK_EQUAL(1, get_number_of_decimal_digits(1));
    BOOST_CHECK_EQUAL(1, get_number_of_decimal_digits(5));
    BOOST_CHECK_EQUAL(1, get_number_of_decimal_digits(9));

    BOOST_CHECK_EQUAL(2, get_number_of_decimal_digits(10));
    BOOST_CHECK_EQUAL(2, get_number_of_decimal_digits(50));
    BOOST_CHECK_EQUAL(2, get_number_of_decimal_digits(99));

    BOOST_CHECK_EQUAL(3, get_number_of_decimal_digits(100));
    BOOST_CHECK_EQUAL(3, get_number_of_decimal_digits(500));
    BOOST_CHECK_EQUAL(3, get_number_of_decimal_digits(999));

    BOOST_CHECK_EQUAL(4, get_number_of_decimal_digits(1000));
    BOOST_CHECK_EQUAL(4, get_number_of_decimal_digits(5000));
    BOOST_CHECK_EQUAL(4, get_number_of_decimal_digits(9999));

    BOOST_CHECK_THROW(get_number_of_decimal_digits(-1), std::invalid_argument);
    BOOST_CHECK_THROW(get_number_of_decimal_digits(-100), std::invalid_argument);
    BOOST_CHECK_THROW(get_number_of_decimal_digits(0), std::invalid_argument);
    BOOST_CHECK_THROW(get_number_of_decimal_digits(10000), std::invalid_argument);
    BOOST_CHECK_THROW(get_number_of_decimal_digits(99999), std::invalid_argument);
}

void Tag_test_tagIdToString() {
    using fixparser::TagConverter;

    const TagConverter& instance0 = TagConverter::instance();
    const TagConverter& instance1 = TagConverter::instance();
    BOOST_CHECK_EQUAL(&instance0, &instance1);

    BOOST_CHECK_EQUAL("1", TagConverter::tagIdToString(1));
    BOOST_CHECK_EQUAL("5", TagConverter::tagIdToString(5));
    BOOST_CHECK_EQUAL("9", TagConverter::tagIdToString(9));
    BOOST_CHECK_EQUAL("100", TagConverter::tagIdToString(100));
    BOOST_CHECK_EQUAL("555", TagConverter::tagIdToString(555));
    BOOST_CHECK_EQUAL("9999", TagConverter::tagIdToString(9999));

    BOOST_CHECK_THROW(TagConverter::tagIdToString(-1), std::invalid_argument);
    BOOST_CHECK_THROW(TagConverter::tagIdToString(-100), std::invalid_argument);
    BOOST_CHECK_THROW(TagConverter::tagIdToString(0), std::invalid_argument);
    BOOST_CHECK_THROW(TagConverter::tagIdToString(10000), std::invalid_argument);
    BOOST_CHECK_THROW(TagConverter::tagIdToString(99999), std::invalid_argument);
}
